package com.futu.ai.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.futu.ai.mapper.Aimapper;
import com.futu.ai.pojo.Attraction;
import com.futu.ai.pojo.ImageRecognitionResponse;
import com.futu.ai.utils.AiUtils;
import com.futu.ai.utils.QiniuUtils;
import com.zhipu.oapi.service.v4.model.ModelData;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * AI服务类
 *
 * @author AI Assistant
 */
@Service
public class AiService {
    private static final String PREFIX = "你就只要回答这个里面的问题比如说我想去旅游有没有推荐的你就推荐几个." +
            "只能回答跟咱这个数据一样的，如果用户说不关于这个的就回答：抱歉我是一个旅游ai助手,你想要我推荐一些好玩的地方吗？,只有用户提问不相关的旅游信息的时候" +
            "此上面用户看不到前面的文字是我的一个前缀跟知识库一样的。这个后面才是用户说的数据前面的数据是我在开发的时候写的，并且你在回答的时候不用说根据数据库中的数据进行回答这写累心的话" +
            "根据用户的情况回答比如用户回答你好那就你应该回答你好需要什么帮助让后在跟用户的情况回答在回答" +
            "前面的数据不是用户说的是开发人员写的前缀，这个后面的数据才是用户说的：";
    /**
     * AI调用 mapper
     * */

    @Resource
    private Aimapper aimapper;

    /**
     * 生成问题回答（同步方式）
     * @param prompt 提示词
     * @return AI生成的回答
     */
    public String generateQuestion(String prompt) {
        List<Attraction> selectAll =aimapper.selectAttractionAll();
        String qianZhuei = selectAll.stream()
                .map(attraction ->
                        "景点名称：" + attraction.getName() +
                                "景点城市：" + attraction.getCity() +
                                "景点详细地址:" + attraction.getAddress() +
                                "景点描述：" + attraction.getDescription() +
                                "图片照片路径" + attraction.getImageUrl() +
                                "景点经度：" + attraction.getLongitude() +
                                "景点纬度：" + attraction.getLatitude()
                )
                .collect(Collectors.joining()) +PREFIX
                ;
        return AiUtils.aiCaller(qianZhuei+prompt);
    }


    public SseEmitter generateQuestionSSE(String prompt) {
        List<Attraction> selectAll =aimapper.selectAttractionAll();
        String qianZhuei = selectAll.stream()
                .map(attraction ->
                        "景点名称：" + attraction.getName() +
                                "景点城市：" + attraction.getCity() +
                                "景点详细地址:" + attraction.getAddress() +
                                "景点描述：" + attraction.getDescription() +
                                "图片照片路径" + attraction.getImageUrl() +
                                "景点经度：" + attraction.getLongitude() +
                                "景点纬度：" + attraction.getLatitude()
                )
                .collect(Collectors.joining()) +PREFIX
                ;
        // 建立 SSE 连接对象，0 表示不超时
        SseEmitter emitter = new SseEmitter(0L);
        // AI 生成的流式响应结果
        Flowable<ModelData> modelDataFlowable = AiUtils.aiCallerFlow(qianZhuei+prompt);
    
        modelDataFlowable
            // 指定观察者的线程池
            .observeOn(Schedulers.io())
            // 从智谱的响应中获取数据
            .map(chunk -> chunk.getChoices().get(0).getDelta().getContent())
            // 去掉响应中多余的空格
            .map(message -> message.replaceAll("\\s", ""))
            // 去掉为空字符串的响应
            .filter(StringUtils::isNotBlank)
            .flatMap(message -> {
                // 将字符串转换为字符数组以便后续业务处理
                List<Character> charList = new ArrayList<>();
                for (char c : message.toCharArray()) {
                    charList.add(c);
                }
                return Flowable.fromIterable(charList);
            })
            .doOnNext(c -> {
                try {
                    // 发送结果
                    emitter.send(c);
                } catch (Exception e) {
                    // 处理异常
                    emitter.completeWithError(e);
                }
            })
            // 当AI响应完毕时关闭SSE
            .doOnComplete(emitter::complete)
            // 处理异常情况
            .doOnError(e -> emitter.completeWithError(e))
            // 订阅AI响应流
            .subscribe();
        
        return emitter;
    }
    
    /**
     * 提取有效JSON字符串
     * 使用正则表达式匹配JSON格式的字符串
     * @param input 包含JSON和其他内容的字符串
     * @return 提取出的JSON字符串，如果没有找到则返回原字符串
     */
    private String extractJsonString(String input) {
        // 尝试找出格式为 {包含内容} 的字符串
        Pattern jsonPattern = Pattern.compile("\\{.*?\\}");
        Matcher matcher = jsonPattern.matcher(input);
        
        // 寻找最长的匹配，这通常是完整的JSON
        String longestMatch = "";
        while (matcher.find()) {
            String match = matcher.group();
            if (match.length() > longestMatch.length()) {
                longestMatch = match;
            }
        }
        
        // 如果找到了JSON格式的字符串，返回它
        if (!longestMatch.isEmpty()) {
            return longestMatch;
        }
        
        // 如果没有找到JSON，尝试清理字符串
        // 移除所有<think>...</think>标签及其内容
        String cleaned = input.replaceAll("<think>.*?</think>", "").trim();
        // 移除<think>之前的所有内容（如果标签没有正确闭合）
        cleaned = cleaned.replaceAll(".*?<think>", "").trim();
        
        return cleaned;
    }
    
    /**
     * 图片识别服务
     * @param imageBase64 图片Base64编码
     * @return 图片识别结果
     */
    public ImageRecognitionResponse recognizeImage(String imageBase64) {
        ImageRecognitionResponse response = new ImageRecognitionResponse();
        
        try {
            // 第一步：上传图片到七牛云
            String imageUrl = QiniuUtils.uploadImage(imageBase64);
            response.setImageUrl(imageUrl);
            
            // 第二步：使用GLM-4V-FLASH模型识别景点
            String imagePrompt = "请识别这张图片中的景点名称。只返回景点名称，不要其他描述。";
            String recognitionResult = AiUtils.imageRecognitionCaller(imageBase64, imagePrompt);
            
            // 提取景点名称（假设模型直接返回景点名称）
            String spotName = recognitionResult.trim();
            response.setSpotName(spotName);
            
            // 第三步：使用GLM-Z1-AIRX推理模型获取坐标信息
            String coordinatePrompt = "给定景点名称：" + spotName + "，请提供该景点的精确地理坐标（经度和纬度），以JSON格式返回，格式为：{\"longitude\": 经度值, \"latitude\": 纬度值, \"description\": \"简短描述\"}。只返回JSON数据，不需要其他说明。";
            String coordinateResult = AiUtils.aiCaller(coordinatePrompt);
            
            // 清理AI返回的结果，提取有效JSON
            String cleanedJson = extractJsonString(coordinateResult);
            
            try {
                // 解析JSON格式的结果
                JSONObject jsonResult = JSON.parseObject(cleanedJson);
                if (jsonResult.containsKey("longitude") && jsonResult.containsKey("latitude")) {
                    response.setLongitude(jsonResult.getDouble("longitude"));
                    response.setLatitude(jsonResult.getDouble("latitude"));
                    response.setDescription(jsonResult.getString("description"));
                    response.setSuccess(true);
                } else {
                    response.setSuccess(false);
                    response.setErrorMessage("无法解析坐标信息");
                }
            } catch (Exception e) {
                // 如果结果不是标准JSON格式，尝试提取坐标信息
                response.setSuccess(false);
                response.setErrorMessage("坐标信息格式不正确: " + e.getMessage() + ", 原始返回: " + coordinateResult);
            }
        } catch (Exception e) {
            response.setSuccess(false);
            response.setErrorMessage("图片处理失败: " + e.getMessage());
        }
        
        return response;
    }
} 